﻿using System;
using FileSecurityManager.BizEntities;
using FileSecurityManager.BizEntities.Extensions;
using FileSecurityManager.DataAccess.Exceptions;

namespace FileSecurityManager.DataAccess
{
    public static class Extensions
    {
        #region Validation Methods
        /// <summary>
        /// Checks the data context for exception.
        /// </summary>
        /// <param name="dataContext">The data context.</param>
        private static void checkDataContextForException(FSMStorageDataContext dataContext)
        {
            if (dataContext == null)
            {
                new ArgumentNullException(ExceptionMessages.DataContextIsNullMessage);
            }
        }

        /// <summary>
        /// Checks the entity for exception.
        /// </summary>
        /// <param name="entity">The entity.</param>
        private static void checkEntityForException(object entity)
        {
            if (entity == null)
            {
                new ArgumentNullException(ExceptionMessages.EntityIsNullMessage);
            }
        }

        /// <summary>
        /// Checks the model and data context for exception.
        /// </summary>
        /// <param name="model">The model item.</param>
        /// <param name="dataContext">The data context.</param>
        private static void checkModelAndDataContextForException(object model, FSMStorageDataContext dataContext)
        {
            checkDataContextForException(dataContext);

            if (model == null)
            {
                new ArgumentNullException(ExceptionMessages.ModelIsNullMessage);
            }
        }

        #endregion

        #region Role
        /// <summary>
        /// Toes the model.
        /// </summary>
        /// <param name="entity">The entity.</param>
        /// <param name="dataContext">The data context.</param>
        /// <returns>Role model</returns>
        public static RoleModel ToModel(this Role entity, FSMStorageDataContext dataContext)
        {
            try
            {
                if (entity == null)
                {
                    return null;
                }

                checkDataContextForException(dataContext);

                var roleModel = new RoleModel
                                    {
                                        ItemId = entity.Id,
                                        RoleName = entity.RoleName,
                                        RoleDescription = entity.RoleDescription
                                    };

                return roleModel;
            }
            catch (Exception ex)
            {
                throw new DataAccessException(
                    string.Format(ExceptionMessages.RoleToRoleModelFailed, ex.Message),
                    ex);
            }
        }

        /// <summary>
        /// Froms the model.
        /// </summary>
        /// <param name="entity">The entity.</param>
        /// <param name="model">The model.</param>
        /// <param name="dataContext">The data context.</param>
        public static void FromModel(this Role entity, RoleModel model, FSMStorageDataContext dataContext)
        {
            try
            {
                checkEntityForException(entity);
                checkModelAndDataContextForException(model, dataContext);

                entity.Id = model.ItemId > 0 ? model.ItemId : 0;
                entity.RoleName = model.RoleName;
                entity.RoleDescription = model.RoleDescription;
            }
            catch (Exception ex)
            {
                throw new DataAccessException(
                    string.Format(ExceptionMessages.RoleModelToRoleFailed, ex.Message),
                    ex);
            }
        }
        #endregion

        #region User

        /// <summary>
        /// Converts user entity the user model.
        /// </summary>
        /// <param name="entity">The entity.</param>
        /// <param name="dataContext">The data context.</param>
        /// <returns>User Model</returns>
        public static UserModel ToModel(this User entity, FSMStorageDataContext dataContext)
        {
            try
            {
                if (entity == null)
                {
                    return null;
                }

                checkDataContextForException(dataContext);

                var userModel = new UserModel
                {
                    ItemId = entity.Id,
                    UserName = entity.UserName,
                    Password = entity.Password.DecryptString(),
                    FirstName = entity.FirstName,
                    MiddleName = entity.MiddleName,
                    LastName = entity.LastName,
                    Position = entity.Position
                };

                UserRole userRoleEntity = entity.UserRole;
                userModel.UserRole = userRoleEntity == null ? null : userRoleEntity.ToModel(dataContext);

                UserOption userOptionEntity = entity.UserOption;
                userModel.UserOptions = userOptionEntity == null ? null : userOptionEntity.ToModel(dataContext);

                return userModel;
            }
            catch (Exception ex)
            {
                throw new DataAccessException(
                    string.Format(ExceptionMessages.UserToUserModelFailed, ex.Message),
                    ex);
            }
        }

        /// <summary>
        /// Froms the model.
        /// </summary>
        /// <param name="entity">The entity.</param>
        /// <param name="model">The model.</param>
        /// <param name="dataContext">The data context.</param>
        public static void FromModel(this User entity, UserModel model, FSMStorageDataContext dataContext)
        {
            try
            {
                checkEntityForException(entity);
                checkModelAndDataContextForException(model, dataContext);

                entity.Id = model.ItemId > 0 ? model.ItemId : 0;
                entity.UserName = model.UserName;
                entity.Password = model.Password.EncryptString();
                entity.FirstName = model.FirstName;
                entity.MiddleName = model.MiddleName;
                entity.LastName = model.LastName;
                entity.Position = model.Position;

                if (model.ItemId > 0)
                {
                    if (entity.UserRole != null)
                    {
                        entity.UserRole.FromModel(model.UserRole, dataContext);
                    }
                    else
                    {
                        entity.UserRole = model.UserRole.ToEntity(dataContext);
                    }

                    if (entity.UserOption != null)
                    {
                        entity.UserOption.FromModel(model.UserOptions, dataContext);
                    }
                    else
                    {
                        entity.UserOption = model.UserOptions.ToEntity(dataContext);
                    }
                }
            }
            catch (Exception ex)
            {
                throw new DataAccessException(
                    string.Format(ExceptionMessages.UserModelToUserFailed, ex.Message),
                    ex);
            }
        }

        /// <summary>
        /// Converts User Model the User entity.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="dataContext">The data context.</param>
        /// <returns>User instance</returns>
        public static User ToEntity(this UserModel model, FSMStorageDataContext dataContext)
        {
            try
            {
                checkModelAndDataContextForException(model, dataContext);
                var user = new User
                               {
                                   Id = model.ItemId > 0 ? model.ItemId : 0,
                                   UserName = model.UserName,
                                   Password = model.Password.EncryptString(),
                                   FirstName = model.FirstName,
                                   MiddleName = model.MiddleName,
                                   LastName = model.LastName,
                                   Position = model.Position,
                               };

                if (model.UserRole != null)
                {
                    user.UserRole = model.UserRole.ToEntity(dataContext);
                }

                if (model.UserOptions != null)
                {
                    user.UserOption = model.UserOptions.ToEntity(dataContext);
                }
                return user;
            }
            catch (Exception ex)
            {
                throw new DataAccessException(
                    string.Format(ExceptionMessages.UserModelToUserFailed, ex.Message),
                    ex);
            }
        }
        #endregion

        #region UserRoles

        /// <summary>
        /// Converts user role to model
        /// </summary>
        /// <param name="entity">The entity.</param>
        /// <param name="dataContext">The data context.</param>
        /// <returns>UserRole Model</returns>
        public static UserRoleModel ToModel(this UserRole entity, FSMStorageDataContext dataContext)
        {
            try
            {
                if (entity == null)
                {
                    return null;
                }

                checkDataContextForException(dataContext);

                var userRoleModel = new UserRoleModel()
                {
                    ItemId = entity.UserId,
                    RoleId = entity.RoleId,
                };

                if (entity.Role != null)
                {
                    userRoleModel.RoleName = entity.Role.RoleName;
                }

                return userRoleModel;
            }
            catch (Exception ex)
            {
                throw new DataAccessException(
                    string.Format("UserRole to UserRoleModel conversion failed.\n {0}.\n", ex.Message),
                    ex);
            }
        }

        /// <summary>
        /// Froms the model.
        /// </summary>
        /// <param name="entity">The entity.</param>
        /// <param name="model">The model.</param>
        /// <param name="dataContext">The data context.</param>
        public static void FromModel(this UserRole entity, UserRoleModel model, FSMStorageDataContext dataContext)
        {
            try
            {
                checkEntityForException(entity);
                checkModelAndDataContextForException(model, dataContext);

                entity.UserId = model.ItemId > 0 ? model.ItemId : 0;
                entity.RoleId = model.RoleId;
            }
            catch (Exception ex)
            {
                throw new DataAccessException(
                    string.Format("UserRole Model to UserRole conversion failed.\n {0}.\n", ex.Message),
                    ex);
            }
        }

        /// <summary>
        /// UserRoleModel to UserRole entity.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="dataContext">The data context.</param>
        /// <returns>UserRole entity</returns>
        public static UserRole ToEntity(this UserRoleModel model, FSMStorageDataContext dataContext)
        {
            try
            {
                checkModelAndDataContextForException(model, dataContext);

                var userRole = new UserRole()
                {
                    UserId = model.ItemId > 0 ? model.ItemId : 0,
                    RoleId = model.RoleId
                };

                return userRole;
            }
            catch (Exception ex)
            {
                throw new DataAccessException(
                    string.Format("UserRole model to UserRole entity conversion failed.\n {0}.\n", ex.Message),
                    ex);
            }
        }
        #endregion

        #region UserOptions

        /// <summary>
        /// Converts user role to model
        /// </summary>
        /// <param name="entity">The entity.</param>
        /// <param name="dataContext">The data context.</param>
        /// <returns>UserOptions Model</returns>
        public static UserOptionsModel ToModel(this UserOption entity, FSMStorageDataContext dataContext)
        {
            try
            {
                if (entity == null)
                {
                    return null;
                }

                checkDataContextForException(dataContext);

                var userOptionsModel = new UserOptionsModel
                                           {
                                               ItemId = entity.UserId,
                                               WorkingDir = entity.WorkingDirectory,
                                               IsExcel = entity.IsExcel ?? true,
                                               IsImages = entity.IsImages ?? true,
                                               IsMusic = entity.IsMusic ?? true,
                                               IsPDF = entity.IsPDF ?? true,
                                               IsVideo = entity.IsVideo ?? true,
                                               IsWord = entity.IsWord ?? true
                                           };
                return userOptionsModel;
            }
            catch (Exception ex)
            {
                throw new DataAccessException(
                    string.Format("UserOptions to UserOptionsModel conversion failed.\n {0}.\n", ex.Message),
                    ex);
            }
        }

        /// <summary>
        /// Froms the model.
        /// </summary>
        /// <param name="entity">The entity.</param>
        /// <param name="model">The model.</param>
        /// <param name="dataContext">The data context.</param>
        public static void FromModel(this UserOption entity, UserOptionsModel model, FSMStorageDataContext dataContext)
        {
            try
            {
                checkEntityForException(entity);
                checkModelAndDataContextForException(model, dataContext);

                entity.UserId = model.ItemId > 0 ? model.ItemId : 0;
                entity.WorkingDirectory = model.WorkingDir;
                entity.IsExcel = model.IsExcel;
                entity.IsImages = model.IsImages;
                entity.IsMusic = model.IsMusic;
                entity.IsPDF = model.IsPDF;
                entity.IsVideo = model.IsVideo;
                entity.IsWord = model.IsWord;
            }
            catch (Exception ex)
            {
                throw new DataAccessException(
                    string.Format("UserOption Model to UserOption conversion failed.\n {0}.\n", ex.Message),
                    ex);
            }
        }

        /// <summary>
        /// UserRoleModel to UserRole entity.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="dataContext">The data context.</param>
        /// <returns>UserRole entity</returns>
        public static UserOption ToEntity(this UserOptionsModel model, FSMStorageDataContext dataContext)
        {
            try
            {
                checkModelAndDataContextForException(model, dataContext);

                var userOption = new UserOption()
                {
                    UserId = model.ItemId > 0 ? model.ItemId : 0,
                    WorkingDirectory = model.WorkingDir,
                    IsExcel = model.IsExcel,
                    IsImages = model.IsImages,
                    IsMusic = model.IsMusic,
                    IsPDF = model.IsPDF,
                    IsVideo = model.IsVideo,
                    IsWord = model.IsWord,
                };

                return userOption;
            }
            catch (Exception ex)
            {
                throw new DataAccessException(
                    string.Format("UserOption model to UserOption entity conversion failed.\n {0}.\n", ex.Message),
                    ex);
            }
        }
        #endregion
    }
}
